package main

import (
	"fmt"
	"image/jpeg"
	"image/png"
	"io"
	"lcss/assets"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

func Index(c *gin.Context) {
	readfs, _ := assets.FS.ReadFile("index.html")
	c.Data(http.StatusOK, "text/html; charset=utf-8", readfs)
}

func Login(c *gin.Context) {
	issuer := "goview"
	var user TSysUser

	if err := c.ShouldBindJSON(&user); err != nil {
		JSONError(c, http.StatusBadRequest, "Invalid token")
		return
	}
	enctypedPass := EncryptPassword(user.Password)
	if err := db.Where("username = ?", user.Username).First(&user).Error; err != nil {
		JSONError(c, 500, "用户或密码错误")
		return
	} else {
		fmt.Println(err)
	}

	if enctypedPass != user.Password {
		JSONError(c, 500, "用户或密码错误")
		return
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"iss":      issuer,
		"username": user.Username,
		"exp":      time.Now().Add(time.Hour * 24).Unix(),
	})
	tokenString, err := token.SignedString([]byte("secret"))
	if err != nil {
		JSONError(c, http.StatusInternalServerError, "Invalid token")
		return
	}
	m := make(map[string]any)
	m["tokenValue"] = tokenString
	m["tokenName"] = "Authorization"
	m["isLogin"] = true
	m["loginId"] = user.Id
	m["loginType"] = "login"
	m["tokenTimeout"] = time.Now().Add(time.Hour * 24).Unix()
	m["sessionTimeout"] = time.Now().Add(time.Hour * 24).Unix()
	m["tokenSessionTimeout"] = time.Now().Add(time.Hour * 24).Unix()
	m["tokenActivityTimeout"] = -1
	m["loginDevice"] = "default-device"
	m["tag"] = nil
	JSONSuccess(c, gin.H{"userinfo": user, "token": m})
}

func GetOssInfo(c *gin.Context) {
	//获取服务器的当前host信息以及对应port
	host := c.Request.Host
	domain := config.Domain
	if domain == "" {
		domain = host
	}
	JSONSuccess(c, gin.H{
		"BucketName": "getuserphoto",
		"bucketURL":  domain + "/static/uploads/goviews/",
	})
}

func Register(c *gin.Context) {
	var user TSysUser
	if err := c.ShouldBindJSON(&user); err != nil {
		JSONError(c, http.StatusBadRequest, "Invalid token")
		return
	}
	user.Id = GenerateID()
	user.Password = EncryptPassword(user.Password)
	if err := db.Create(&user).Error; err != nil {
		JSONError(c, 500, err.Error())
		return
	} else {
		JSONSuccess(c, user)
	}
}

// 吊销token，并退出登录
func Logout(c *gin.Context) {
	JSONSuccess(c, gin.H{})
}

func ProjectCreate(c *gin.Context) {
	// 从JWT claims中获取当前用户信息
	claims, exists := c.Get("claims")
	if !exists {
		JSONError(c, http.StatusUnauthorized, "未授权访问")
		return
	}

	// 获取用户名
	claimsMap := claims.(jwt.MapClaims)
	username := claimsMap["username"].(string)

	// 查询用户ID
	var user TSysUser
	if err := db.Where("username = ?", username).First(&user).Error; err != nil {
		JSONError(c, http.StatusInternalServerError, "获取用户信息失败")
		return
	}

	var project TGoviewProject
	if err := c.ShouldBindJSON(&project); err != nil {
		JSONError(c, http.StatusBadRequest, "Invalid token")
		return
	}
	project.Id = GenerateID()

	project.CreateUserId = user.Id                                // 设置项目创建者ID
	project.CreateTime = time.Now().Format("2006-01-02 15:04:05") // 设置创建时间

	err := db.Create(&project).Error
	if err != nil {
		JSONError(c, 500, err.Error())
		return
	} else {
		JSONSuccess(c, project)
	}
}

func ProjectEdit(c *gin.Context) {
	var project TGoviewProject
	if err := c.ShouldBindJSON(&project); err != nil {
		JSONError(c, http.StatusBadRequest, "Invalid token")
		return
	}
	tProj := TGoviewProject{}
	db.Model(&TGoviewProject{}).Where("id = ?", project.Id).First(&tProj)
	if tProj.IndexImage != project.IndexImage && project.IndexImage != "" {
		tProj.IndexImage = project.IndexImage
	}
	if tProj.ProjectName != project.ProjectName && project.ProjectName != "" {
		tProj.ProjectName = project.ProjectName
	}
	if tProj.Remarks != project.Remarks && project.Remarks != "" {
		tProj.Remarks = project.Remarks
	}

	if err := db.Save(&tProj).Error; err != nil {
		JSONError(c, 500, err.Error())
		return
	} else {
		JSONSuccess(c, project)
	}
}

func ProjectDelete(c *gin.Context) {
	var project TGoviewProject
	//获取get参数
	ids := c.Query("ids")
	fmt.Println("id", ids)
	if err := db.Model(&TGoviewProject{}).Where("id = ?", ids).Update("is_delete", 1).Error; err != nil {
		JSONError(c, 500, err.Error())
		return
	} else {
		JSONSuccess(c, project)
	}
}

func PorjectListGet(c *gin.Context) {
	// 从JWT claims中获取当前用户信息
	claims, exists := c.Get("claims")
	if !exists {
		JSONError(c, http.StatusUnauthorized, "未授权访问")
		return
	}

	// 获取用户名
	claimsMap := claims.(jwt.MapClaims)
	username := claimsMap["username"].(string)

	// 查询用户ID
	var user TSysUser
	if err := db.Where("username = ?", username).First(&user).Error; err != nil {
		JSONError(c, http.StatusInternalServerError, "获取用户信息失败")
		return
	}

	// 从查询参数中获取页码和每页数量
	page, _ := strconv.Atoi(c.Query("page"))
	pageSize, _ := strconv.Atoi(c.Query("pageSize"))

	// 设置默认值，避免未提供查询参数时的错误
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 10
	}

	// 计算偏移量
	offset := (page - 1) * pageSize

	// 查询数据库，只获取当前用户的项目列表
	var project []TGoviewProject
	db.Offset(offset).Where("is_delete = ? AND create_user_id = ?", 0, user.Id).Limit(pageSize).Find(&project)

	JSONSuccess(c, project)
}

func ProjectPublish(c *gin.Context) {
	// {
	// 	"id": "686921059995357184", //项目主键
	// 	"state": "-1" //项目状态[-1未发布,1发布]
	// 	}
	//gin获取post参数
	var project TGoviewProject
	if err := c.ShouldBindJSON(&project); err != nil {
		JSONError(c, http.StatusBadRequest, "Invalid Data")
		return
	}
	if err := db.Model(&TGoviewProject{}).Where("id = ?", project.Id).Update("state", project.State).Error; err != nil {
		JSONError(c, 500, err.Error())
		return
	} else {
		JSONSuccess(c, project)
	}
}

func ProjectDataGet(c *gin.Context) {
	var project TGoviewProject
	// 从查询参数中获取页码和每页数量
	projectId := c.DefaultQuery("projectId", "")
	var projectData TGoviewProjectData
	err := db.Where("project_id = ?", projectId).First(&projectData).Error
	db.Model(&TGoviewProject{}).Where("id = ?", projectId).First(&project)
	if err != nil {
		if err.Error() == "record not found" {
			JSONSuccess(c, nil)
			return
		} else {
			JSONError(c, 500, err.Error())
			return
		}

	} else {
		JSONSuccess(c, gin.H{
			"content":      projectData.Content,
			"createTime":   project.CreateTime,
			"createUserId": project.CreateUserId,
			"indexImage":   project.IndexImage,
			"id":           project.Id,
			"isDelete":     project.IsDelete,
			"projectName":  project.ProjectName,
			"state":        project.State,
			"remarks":      project.Remarks,
		})
	}
}

func ProjectDataSave(c *gin.Context) {
	var projectData TGoviewProjectData
	projectId := c.DefaultPostForm("projectId", "")
	content := c.DefaultPostForm("content", "")
	if err := db.Where("project_id = ?", projectId).First(&projectData).Error; err != nil {
		err := db.Save(&TGoviewProjectData{Id: GenerateID(),
			ProjectId:  projectId,
			Content:    content,
			CreateTime: time.Now().Format("2006-01-02 15:04:05")}).Error
		if err != nil {
			JSONError(c, 500, err.Error())
			return
		}
	} else {
		projectData.Content = content
		if err := db.Save(&projectData).Error; err != nil {
			JSONError(c, 500, err.Error())
			return
		}
	}
	JSONSuccess(c, projectData)
}

func ProjectUpload(c *gin.Context) {
	file, header, err := c.Request.FormFile("object")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "File not provided"})
		return
	}
	defer file.Close()

	// 生成文件名和扩展名
	fileName := header.Filename
	extension := filepath.Ext(fileName)
	//获取文件大小
	fileSize := header.Size

	// 保存文件到指定目录
	savePath := "./static/uploads/goviews"
	if err := os.MkdirAll(savePath, os.ModePerm); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create upload directory"})
		return
	}
	// 获取文件的真实物理路径
	realPath, err := filepath.Abs(savePath)

	filePath := filepath.Join(savePath, fileName)

	// 如果是图片文件，先进行压缩
	if strings.HasPrefix(header.Header.Get("Content-Type"), "image/") {
		// 创建临时文件
		tmpFile, err := os.CreateTemp("", "img-*"+extension)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create temp file"})
			return
		}
		defer os.Remove(tmpFile.Name())
		defer tmpFile.Close()

		// 先保存到临时文件
		_, err = io.Copy(tmpFile, file)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save temp file"})
			return
		}

		// 重新打开临时文件进行压缩
		tmpFile.Seek(0, 0)
		img, err := jpeg.Decode(tmpFile)
		if err != nil {
			// 如果不是JPEG格式，尝试PNG
			tmpFile.Seek(0, 0)
			img, err = png.Decode(tmpFile)
			if err != nil {
				// 直接保存原始文件
				out, err := os.Create(filePath)
				if err != nil {
					c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file"})
					return
				}
				defer out.Close()
				tmpFile.Seek(0, 0)
				_, err = io.Copy(out, tmpFile)
				if err != nil {
					c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"})
					return
				}
				return
			}
		}

		// 创建输出文件
		out, err := os.Create(filePath)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file"})
			return
		}
		defer out.Close()

		var opt jpeg.Options
		// 压缩图片质量
		opt.Quality = int(config.PCQ)
		err = jpeg.Encode(out, img, &opt)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to compress image"})
			return
		}
	} else {
		// 非图片文件直接保存
		out, err := os.Create(filePath)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file"})
			return
		}
		defer out.Close()

		_, err = io.Copy(out, file)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"})
			return
		}
	}

	var t_sys_file = TSysFile{
		FileName:     fileName,
		FileSuffix:   extension,
		FileSize:     fileSize,
		CreateTime:   time.Now().Format("2006-01-02 15:04:05"),
		VirtualKey:   "oss",
		RelativePath: savePath,
		AbsolutePath: realPath,
	}
	// 将文件信息保存到数据库
	var existingFile TSysFile
	err = db.Where("file_name = ?", fileName).First(&existingFile).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			// 文件不存在，创建新记录
			t_sys_file.Id = GenerateID()
			db.Create(&t_sys_file)
		} else {
			// 其他数据库错误
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error: " + err.Error()})
			return
		}
	} else {
		// 文件已存在，更新记录
		t_sys_file.Id = existingFile.Id
		db.Save(&t_sys_file)
	}
	JSONSuccess(c, gin.H{
		"fileName":     t_sys_file.FileName,
		"fileSize":     t_sys_file.FileSize,
		"fileSuffix":   t_sys_file.FileSuffix,
		"virtualKey":   t_sys_file.VirtualKey,
		"relativePath": t_sys_file.RelativePath,
		"absolutePath": t_sys_file.AbsolutePath,
		"id":           t_sys_file.Id,
		"createTime":   t_sys_file.CreateTime,
	})

}
